package edu.cuny.baruch.cis9590.library.gui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import edu.cuny.baruch.cis9590.library.database.BookDAO;
import edu.cuny.baruch.cis9590.library.database.BorrowDAO;
import edu.cuny.baruch.cis9590.library.database.HoldDAO;
import edu.cuny.baruch.cis9590.library.database.PatronDAO;
import edu.cuny.baruch.cis9590.library.database.PurchaseDAO;
import edu.cuny.baruch.cis9590.library.entities.Book;
import edu.cuny.baruch.cis9590.library.entities.Borrow;
import edu.cuny.baruch.cis9590.library.entities.Hold;
import edu.cuny.baruch.cis9590.library.entities.Purchase;

final class BookSearchPanel extends LibraryPanel {
    
    private final BookDAO bookDAO;
    private final BookTable bookTable;
    private final BorrowDAO borrowDAO;
    private final JButton borrowButton;
    private final JButton holdButton;
    private final HoldDAO holdDAO;
    private final LibraryGUI libraryGUI;
    private final PatronDAO patronDAO;
    private final JButton purchaseButton;
    private final PurchaseDAO purchaseDAO;
    private final JButton removeButton;
    private final JComboBox searchComboBox;
    private final JTextField searchField;
    private final JButton sellButton;
    
    public BookSearchPanel(LibraryGUI libraryGUI) {
        this.libraryGUI = libraryGUI;
        this.bookDAO = new BookDAO();
        this.borrowDAO = new BorrowDAO();
        this.holdDAO = new HoldDAO();
        this.patronDAO = new PatronDAO();
        this.purchaseDAO = new PurchaseDAO();
        
        GridBagLayout gridBagLayout = new GridBagLayout();
        gridBagLayout.columnWidths = new int[]{0, 0, 0, 0, 0, 0, 0, 0};
        gridBagLayout.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0};
        gridBagLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
        gridBagLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 1.0, 0.0, 0.0, Double.MIN_VALUE};
        setLayout(gridBagLayout);
        
        searchComboBox = new JComboBox();
        searchComboBox.setModel(new DefaultComboBoxModel(new String[] {"Title", "Author", "Call"}));
        GridBagConstraints gbc_searchComboBox = new GridBagConstraints();
        gbc_searchComboBox.insets = new Insets(0, 0, 5, 5);
        gbc_searchComboBox.fill = GridBagConstraints.HORIZONTAL;
        gbc_searchComboBox.gridx = 2;
        gbc_searchComboBox.gridy = 1;
        add(searchComboBox, gbc_searchComboBox);
        
        searchField = new JTextField();
        GridBagConstraints gbc_searchField = new GridBagConstraints();
        gbc_searchField.insets = new Insets(0, 0, 5, 5);
        gbc_searchField.fill = GridBagConstraints.HORIZONTAL;
        gbc_searchField.gridx = 3;
        gbc_searchField.gridy = 1;
        add(searchField, gbc_searchField);
        searchField.setColumns(20);
        
        JButton searchButton = new JButton("Search");
        GridBagConstraints gbc_btnSearch = new GridBagConstraints();
        gbc_btnSearch.anchor = GridBagConstraints.WEST;
        gbc_btnSearch.insets = new Insets(0, 0, 5, 5);
        gbc_btnSearch.gridx = 4;
        gbc_btnSearch.gridy = 1;
        add(searchButton, gbc_btnSearch);
        searchButton.addActionListener(new BookSearchActionListener());
        
        JScrollPane scrollPane = new JScrollPane();
        GridBagConstraints gbc_scrollPane = new GridBagConstraints();
        gbc_scrollPane.gridwidth = 5;
        gbc_scrollPane.insets = new Insets(0, 0, 5, 5);
        gbc_scrollPane.fill = GridBagConstraints.BOTH;
        gbc_scrollPane.gridx = 1;
        gbc_scrollPane.gridy = 3;
        add(scrollPane, gbc_scrollPane);
        
        bookTable = new BookTable();
        bookTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        bookTable.getSelectionModel().addListSelectionListener(new BookSearchSelectionListener());
        bookTable.setFillsViewportHeight(true);
        scrollPane.setViewportView(bookTable);
        
        purchaseButton = new JButton("Purchase");
        purchaseButton.addActionListener(new BookPurchaseActionListener());
        purchaseButton.setEnabled(false);
        GridBagConstraints gbc_btnBuy = new GridBagConstraints();
        gbc_btnBuy.insets = new Insets(0, 0, 5, 5);
        gbc_btnBuy.gridx = 1;
        gbc_btnBuy.gridy = 4;
        add(purchaseButton, gbc_btnBuy);
        
        holdButton = new JButton("Hold");
        holdButton.addActionListener(new BookHoldActionListener());
        holdButton.setEnabled(false);
        GridBagConstraints gbc_Hold = new GridBagConstraints();
        gbc_Hold.insets = new Insets(0, 0, 5, 5);
        gbc_Hold.gridx = 2;
        gbc_Hold.gridy = 4;
        add(holdButton, gbc_Hold);

        borrowButton = new JButton("Borrow");
        borrowButton.addActionListener(new BookBorrowActionListener());
        borrowButton.setEnabled(false);
        GridBagConstraints gbc_btnBorrow = new GridBagConstraints();
        gbc_btnBorrow.insets = new Insets(0, 0, 5, 5);
        gbc_btnBorrow.gridx = 3;
        gbc_btnBorrow.gridy = 4;
        add(borrowButton, gbc_btnBorrow);
        
        sellButton = new JButton("Sell");
        sellButton.addActionListener(new BookSellActionListener());
        sellButton.setEnabled(false);
        GridBagConstraints gbc_btnSell = new GridBagConstraints();
        gbc_btnSell.insets = new Insets(0, 0, 5, 5);
        gbc_btnSell.gridx = 4;
        gbc_btnSell.gridy = 4;
        add(sellButton, gbc_btnSell);
        
        removeButton = new JButton("Remove");
        removeButton.addActionListener(new BookRemoveActionListener());
        removeButton.setEnabled(false);
        GridBagConstraints gbc_btnRemove = new GridBagConstraints();
        gbc_btnRemove.insets = new Insets(0, 0, 5, 5);
        gbc_btnRemove.gridx = 5;
        gbc_btnRemove.gridy = 4;
        add(removeButton, gbc_btnRemove);
    }
    
    private int getCurrentUserId() {
        return libraryGUI.getCurrentUser().getPatronId();
    }
    
    private final class BookSearchActionListener implements ActionListener {
        @Override public void actionPerformed(ActionEvent e) {
            String searchText = searchField.getText();
            List<Book> books;
            switch (searchComboBox.getSelectedIndex()) {
                case 0:
                    books = bookDAO.getByTitle(searchText);
                    break;
                case 1:
                    books = bookDAO.getByAuthor(searchText);
                    break;
                case 2:
                    books = bookDAO.getByCallNumber(searchText);
                    break;
                default:
                    books = bookDAO.getAll();
                    break;
            }
            bookTable.setBooks(books);
        }
    }
    
    private abstract class BookActionListener implements ActionListener {
        @Override public final void actionPerformed(ActionEvent e) {
            Book book = bookTable.getSelectedBook();
            updateBook(book);
            bookDAO.update(book);
            bookTable.refresh();
        }
        protected abstract void updateBook(Book book);
    }
    
    private final class BookPurchaseActionListener extends BookActionListener {
        @Override protected void updateBook(Book book) {
            int patronId;
            try {
                String input = JOptionPane.showInputDialog(BookSearchPanel.this, "Enter purchasing patron's ID");
                patronId = Integer.parseInt(input);
                if (patronDAO.getById(patronId) == null) {
                    throw new NumberFormatException();
                }
            } catch (NumberFormatException e) {
                JOptionPane.showMessageDialog(BookSearchPanel.this, "Invalid Patron ID");
                return;
            }
            
            String answer = JOptionPane.showInputDialog(BookSearchPanel.this, "Enter amount paid");
            float price;
            try {
                price = Math.round(Float.parseFloat(answer) * 100) / 100;
                if (price <= 0) {
                    throw new NumberFormatException();
                }
            } catch (NumberFormatException e) {
                JOptionPane.showMessageDialog(BookSearchPanel.this, "Incorrect dollar amount");
                return;
            }
            
            book.setStatus('P');
            purchaseDAO.insert(new Purchase(book.getId(), patronId, price));
        }
    }
    
    private final class BookHoldActionListener extends BookActionListener {
        @Override protected void updateBook(Book book) {
            holdDAO.insert(new Hold(book.getId(), getCurrentUserId(), new Date()));
        }
    }
    
    private final class BookRemoveActionListener extends BookActionListener {
        @Override protected void updateBook(Book book) {
            int answer = JOptionPane.showConfirmDialog(BookSearchPanel.this,
                "Confirm you wish to remove " + book.getTitle(), "Removal confirmation", JOptionPane.YES_NO_OPTION);
            if (answer == JOptionPane.YES_OPTION) {
                book.setStatus('D');
            }
        }
    }
    
    private final class BookSellActionListener extends BookActionListener {
        @Override protected void updateBook(Book book) {
            book.setStatus('S');
        }
    }
    
    private final class BookBorrowActionListener extends BookActionListener {
        @Override protected void updateBook(Book book) {
        	int patronId;
        	try {
        		String input = JOptionPane.showInputDialog(BookSearchPanel.this, "Enter Patron ID:");
        		patronId = Integer.parseInt(input);
        		if (patronDAO.getById(patronId) == null) {
        			throw new NumberFormatException();
        		}
        	} catch (NumberFormatException e) {
        		JOptionPane.showMessageDialog(BookSearchPanel.this, "Invalid Patron ID.");
        		return;
        	}
        	
            book.setStatus('B');
            Date borrowDate = new Date();
            Calendar dueDate = Calendar.getInstance();
            dueDate.setTime(borrowDate);
            dueDate.add(Calendar.WEEK_OF_YEAR, 3);
            borrowDAO.insert(new Borrow(book.getId(), patronId, borrowDate, dueDate.getTime()));
        }
    }
    
    private final class BookSearchSelectionListener implements ListSelectionListener {
        @Override public void valueChanged(ListSelectionEvent e) {
            Book selectedBook = bookTable.getSelectedBook();
            if (selectedBook == null) {
                borrowButton.setEnabled(false);
                holdButton.setEnabled(false);
                purchaseButton.setEnabled(false);
                removeButton.setEnabled(false);
                sellButton.setEnabled(false);
            } else {
                borrowButton.setEnabled(selectedBook.getStatus() == 'A');
                holdButton.setEnabled(selectedBook.getStatus() == 'B');
                purchaseButton.setEnabled(selectedBook.getStatus() == 'S');
                removeButton.setEnabled(selectedBook.getStatus() == 'A' || selectedBook.getStatus() == 'S');
                sellButton.setEnabled(selectedBook.getStatus() == 'A');
            }
        }
    }
    
    @Override
    public void clear() {
        searchComboBox.setSelectedIndex(0);
        searchField.setText("");
        bookTable.clear();
    }
    
    @Override
    public void setAccessLevel(int accessLevel) {
        switch (accessLevel) {
            case 3:
                removeButton.setVisible(true);
                sellButton.setVisible(true);
            case 2:
                borrowButton.setVisible(true);
                purchaseButton.setVisible(true);
            case 1:
                break;
            case 0:
                borrowButton.setVisible(false);
                purchaseButton.setVisible(false);
                removeButton.setVisible(false);
                sellButton.setVisible(false);
                bookTable.clear();
                break;
        }
    }
}
